package com.palm.platform;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.palm.core.data.Pair;
import com.palm.core.util.StringUtil;
import com.palm.core.util.TokenUtil;
import com.palm.platform.domain.UserInfo;
import org.noear.solon.SolonApp;
import org.noear.solon.core.handle.Context;

import java.util.concurrent.TimeUnit;


public final class Current {
    private static final String userKeyAttrName = "@user_key_";
    public static final String USER = "";
    public static final String MEMBER = "m";
    private static Cache<String, Pair<Long, UserInfo>> allUsers;
    private static int timeout = 1800;//s
    private static boolean tokenUseCookie = false;//0 cookie,1 header
    public static void init(SolonApp app) {
        //app.cfg()
        timeout = app.cfg().getInt("server.session.timeout", 1800);
        tokenUseCookie = "cookie".equals(app.cfg().get("server.token_type","header"));
        allUsers = Caffeine.newBuilder().expireAfterAccess(timeout, TimeUnit.SECONDS).build();
    }

    public static Context context() {
        return Context.current();
    }

    public static String getUserToken(String type) {
        String keyName = userKeyAttrName + type;
        Context ctx = context();
        String userToken = ctx.attr(keyName);
        if (StringUtil.isEmpty(userToken)) {
            if(tokenUseCookie){
                userToken = ctx.cookie(getCookieName(type));
            }else{
                userToken = ctx.header(getTokenName(type));
                if(StringUtil.isEmpty(userToken)){
                    userToken = ctx.param("_token");
                }
            }

            if (StringUtil.isNotEmpty(userToken)) {
                ctx.attrSet(keyName, userToken);
            }
        }
        return userToken;
    }

    /**
     * 踢出全部用户。注意：虽然踢出了，但是用依然可以凭借token重新登录。
     */
    public static void invalidateAllUser(){
        allUsers.cleanUp();
    }

    public static UserInfo user() {
        return user(USER);//(UserInfo) context().session(userKeyAttrName);
    }
    public static void logout(){
        logout(USER);
    }
    public static void logout(String userType){
        String token = getUserToken(userType);
        if(StringUtil.isNotEmpty(token)){
            allUsers.invalidate(token);
            if(tokenUseCookie){
                context().cookieRemove(getCookieName(userType));
            }else{
                context().headerSet("rtk","true");
            }
        }
    }
    public static UserInfo user(String type) {
        String token = getUserToken(type);
        if (StringUtil.isEmpty(token)) {
            return null;
        }
        Pair<Long, UserInfo> cacheUser = allUsers.getIfPresent(token);
        if (cacheUser == null) {
            return null;
        }
        long now=System.currentTimeMillis()/1000;
        long t=cacheUser.getKey();
        UserInfo userInfo=cacheUser.getValue();
        if(now>t-300){//不足5分钟的时候更新token
            allUsers.invalidate(token);
            Context ctx = context();
            String newTk= TokenUtil.token(userInfo.getUsername(), userInfo.getPassword(), timeout);
            ctx.attr(userKeyAttrName + type,newTk);
            long timeExpired=System.currentTimeMillis()/1000+timeout;
            cacheUser.setKey(timeExpired);
            allUsers.put(newTk,cacheUser);
            setToken(type,newTk);
        }
        return userInfo;
    }

    public static void login(UserInfo userInfo) {
        login(USER, userInfo);
    }

    public static void login(String type, UserInfo userInfo) {
        String ntk = TokenUtil.token(userInfo.getUsername(), userInfo.getPassword(), timeout);
        context().attrSet(userKeyAttrName + type,ntk);
        long timeExpired=System.currentTimeMillis()/1000+timeout;
        Pair<Long, UserInfo> ud = new Pair<>(timeExpired, userInfo);
        allUsers.put(ntk, ud);

        setToken(userInfo.getUserType(), ntk);
    }
    private static String getCookieName(String userType){
        return "_t"+userType;
    }
    //token不存在多用户登录的问题
    private static String getTokenName(String userType){
        return "token";
    }
    private static void setToken(String userType, String token) {
        Context ctx = context();
        if(tokenUseCookie){
            ctx.cookieSet(getCookieName(userType), token);
        }else{
            ctx.headerSet(getTokenName(userType),token);
        }


    }
}
